#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "ping/ping_sock.h"
#include "lwip/inet.h"
#include "lwip/ip_addr.h"
#include "ping_task.h"

#define PING_TAG "ping_task"

// 调试日志控制
#define PING_DEBUG 0
#if PING_DEBUG
#define PING_LOGD(...) ESP_LOGI(PING_TAG, __VA_ARGS__)
#else
#define PING_LOGD(...)
#endif

static esp_ping_handle_t s_ping_handle = NULL;
static int s_ping_timeout_count = 0;
static esp_netif_t *s_netif = NULL;
static TaskHandle_t s_ping_task_handle = NULL;
static volatile bool s_ping_task_running = false;
static ping_task_config_t s_config;
static bool s_using_backup_target = false;

// ping回调函数
static void on_ping_success(esp_ping_handle_t hdl, void *args)
{
    uint8_t ttl;
    uint16_t seqno;
    uint32_t elapsed_time, recv_len;
    ip_addr_t target_addr;
    esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
    esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
    esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
    esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
    esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
    PING_LOGD("[OK] %d bytes from %s icmp_seq=%d ttl=%d time=%d ms",
              (int)recv_len, inet_ntoa(target_addr), seqno, ttl, (int)elapsed_time);
    s_ping_timeout_count = 0;
    s_using_backup_target = false; // 恢复主目标
}

static void on_ping_timeout(esp_ping_handle_t hdl, void *args)
{
    uint16_t seqno;
    ip_addr_t target_addr;
    esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
    esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
    ESP_LOGW(PING_TAG, "[Timeout] From %s icmp_seq=%d timeout", inet_ntoa(target_addr), seqno);
    s_ping_timeout_count++;

    if (s_ping_timeout_count >= s_config.timeout_threshold)
    {
        ESP_LOGE(PING_TAG, "Ping failed %d times, restarting DHCP", s_ping_timeout_count);
        esp_netif_dhcpc_stop(s_netif);
        esp_netif_dhcpc_start(s_netif); // DHCP重试会触发ARP刷新
        s_ping_timeout_count = 0;

        // 如果主目标失败，尝试备用目标（解决ICMP禁用问题）
        // if (!s_using_backup_target && s_config.backup_ping_target != NULL)
        // {
        //     ESP_LOGW(PING_TAG, "Switching to backup ping target: %s", s_config.backup_ping_target);
        //     s_using_backup_target = true;
        //     esp_ping_stop(s_ping_handle);
        //     esp_ping_delete_session(s_ping_handle);
        //     s_ping_handle = NULL;
        // }
        // else
        // {
        //     // 停止ping会话，等待轮询重新启动
        //     esp_ping_stop(s_ping_handle);
        //     esp_ping_delete_session(s_ping_handle);
        //     s_ping_handle = NULL;
        //     s_using_backup_target = false;
        //     ESP_LOGW(PING_TAG, "waiting to restart ping session.");
        // }
    }
}

static void on_ping_end(esp_ping_handle_t hdl, void *args)
{
    uint32_t transmitted, received, total_time_ms;
    esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
    esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
    esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
    ESP_LOGI(PING_TAG, "[END] %d packets transmitted, %d received, time %dms",
             (int)transmitted, (int)received, (int)total_time_ms);
}

// 启动ping会话
static esp_err_t start_ping_session(void)
{
    if (s_ping_handle != NULL)
    {
        ESP_LOGW(PING_TAG, "Ping session already running");
        return ESP_ERR_INVALID_STATE;
    }

    // 获取IP和网关
    esp_netif_ip_info_t ip_info;
    esp_err_t ret = esp_netif_get_ip_info(s_netif, &ip_info);
    if (ret != ESP_OK || ip_info.ip.addr == 0 || ip_info.gw.addr == 0)
    {
        ESP_LOGW(PING_TAG, "No valid IP or gateway");
        return ESP_ERR_INVALID_STATE;
    }

    // 检查DHCP状态（解决租约失效问题）
    esp_netif_dhcp_status_t dhcp_status;
    ret = esp_netif_dhcpc_get_status(s_netif, &dhcp_status);
    if (ret != ESP_OK || dhcp_status != ESP_NETIF_DHCP_STARTED)
    {
        ESP_LOGW(PING_TAG, "Invalid DHCP status");
        return ESP_ERR_INVALID_STATE;
    }

    // 配置ping目标（主目标或备用目标）
    esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG();
    if (s_using_backup_target && s_config.backup_ping_target != NULL)
    {
        ip_addr_t backup_addr;
        ipaddr_aton(s_config.backup_ping_target, &backup_addr);
        ping_config.target_addr = backup_addr;
    }
    else
    {
        // 修正：直接设置网关地址为ip_addr_t
        ip_addr_set_ip4_u32(&ping_config.target_addr, ip_info.gw.addr);
    }
    ping_config.count = ESP_PING_COUNT_INFINITE;
    ping_config.interval_ms = s_config.ping_interval_ms;
    ping_config.timeout_ms = s_config.ping_timeout_ms;
    ping_config.task_prio = s_config.task_priority;

    esp_ping_callbacks_t cbs = {
        .on_ping_success = on_ping_success,
        .on_ping_timeout = on_ping_timeout,
        .on_ping_end = on_ping_end,
        .cb_args = NULL};

    ret = esp_ping_new_session(&ping_config, &cbs, &s_ping_handle);
    if (ret != ESP_OK)
    {
        ESP_LOGE(PING_TAG, "Failed to create ping session: %s", esp_err_to_name(ret));
        return ret;
    }

    ret = esp_ping_start(s_ping_handle);
    if (ret != ESP_OK)
    {
        ESP_LOGE(PING_TAG, "Failed to start ping: %s", esp_err_to_name(ret));
        esp_ping_delete_session(s_ping_handle);
        s_ping_handle = NULL;
        return ret;
    }

    ESP_LOGI(PING_TAG, "Ping session started, target: %s",
             s_using_backup_target ? s_config.backup_ping_target : inet_ntoa(ip_info.gw));
    return ESP_OK;
}

// ping任务
static void ping_task(void *pvParameters)
{
    esp_netif_t *netif = (esp_netif_t *)pvParameters;
    s_netif = netif;
    bool last_ip_valid = false;
    int dhcp_retry_count = 0;

    while (s_ping_task_running)
    {
        // 检查IP和DHCP状态
        esp_netif_ip_info_t ip_info;
        esp_err_t ret = esp_netif_get_ip_info(netif, &ip_info);
        esp_netif_dhcp_status_t dhcp_status;
        esp_netif_dhcpc_get_status(netif, &dhcp_status);
        bool link_status = true; // 默认假设链路正常
        // if (s_config.enable_link_check && s_config.eth_handle != NULL) {
        //     esp_eth_ioctl(s_config.eth_handle, ETH_CMD_G_LINK, &link_status); // 链路状态检查
        //     PING_LOGD("Link status: %s", link_status ? "up" : "down");
        // }
        bool ip_valid = (ret == ESP_OK && ip_info.ip.addr != 0 && ip_info.gw.addr != 0 &&
                         dhcp_status == ESP_NETIF_DHCP_STARTED && link_status);

        PING_LOGD("ip_valid: %d, last_ip_valid: %d", ip_valid, last_ip_valid);

        if (ip_valid && !last_ip_valid)
        {
            // IP从无效变为有效，启动ping
            if (start_ping_session() == ESP_OK)
            {
                last_ip_valid = true;
                dhcp_retry_count = 0;
            }
            else
            {
                // 启动失败，重试DHCP
                if (dhcp_retry_count < 3)
                {
                    ESP_LOGW(PING_TAG, "Ping session failed, retry DHCP (%d/3)", dhcp_retry_count + 1);
                    esp_netif_dhcpc_stop(netif);
                    esp_netif_dhcpc_start(netif); // DHCP重试触发ARP刷新
                    dhcp_retry_count++;
                }
            }
        }
        else if (!ip_valid && last_ip_valid)
        {
            // IP从有效变为无效，停止ping
            if (s_ping_handle != NULL)
            {
                esp_ping_stop(s_ping_handle);
                esp_ping_delete_session(s_ping_handle);
                s_ping_handle = NULL;
                ESP_LOGW(PING_TAG, "Ping session stopped due to IP loss");
            }
            last_ip_valid = false;
            dhcp_retry_count = 0;
            esp_netif_dhcpc_stop(netif);
            esp_netif_dhcpc_start(netif); // DHCP重试触发ARP刷新
        }
        else if (!ip_valid && dhcp_retry_count < 3)
        {
            // IP持续无效，重试DHCP（解决快速插拔和DHCP响应慢）
            ESP_LOGW(PING_TAG, "No IP, retry DHCP (%d/3)", dhcp_retry_count + 1);
            esp_netif_dhcpc_stop(netif);
            esp_netif_dhcpc_start(netif);
            dhcp_retry_count++;
        }

        // 监控堆内存（量产调试）
        PING_LOGD("Free heap: %d bytes", (int)esp_get_free_heap_size());

        vTaskDelay(pdMS_TO_TICKS(s_config.poll_interval_ms));
    }

    // 清理资源
    if (s_ping_handle != NULL)
    {
        esp_ping_stop(s_ping_handle);
        esp_ping_delete_session(s_ping_handle);
        s_ping_handle = NULL;
    }
    s_netif = NULL;
    s_ping_task_handle = NULL;
    s_using_backup_target = false;
    ESP_LOGI(PING_TAG, "Ping task stopped");
    vTaskDelete(NULL);
}

// 默认配置
void ping_task_config_default(ping_task_config_t *config)
{
    if (config == NULL)
    {
        return;
    }
    config->poll_interval_ms = PING_TASK_DEFAULT_POLL_INTERVAL_MS;
    config->ping_interval_ms = PING_TASK_DEFAULT_PING_INTERVAL_MS;
    config->ping_timeout_ms = PING_TASK_DEFAULT_PING_TIMEOUT_MS;
    config->timeout_threshold = PING_TASK_DEFAULT_TIMEOUT_THRESHOLD;
    config->task_stack_size = PING_TASK_DEFAULT_TASK_STACK_SIZE;
    config->task_priority = PING_TASK_DEFAULT_TASK_PRIORITY;
    config->enable_link_check = false;
    config->eth_handle = NULL;
    config->backup_ping_target = "8.8.8.8"; // 默认备用目标
}

// 启动ping任务
esp_err_t ping_task_start(esp_netif_t *netif, const ping_task_config_t *config)
{
    if (netif == NULL || config == NULL)
    {
        ESP_LOGE(PING_TAG, "Invalid netif or config");
        return ESP_ERR_INVALID_ARG;
    }

    if (s_ping_task_handle != NULL || s_ping_task_running)
    {
        ESP_LOGW(PING_TAG, "Ping task already running");
        return ESP_ERR_INVALID_STATE;
    }

    // 保存配置
    memcpy(&s_config, config, sizeof(ping_task_config_t));

    // 验证配置
    if (s_config.poll_interval_ms < 100 || s_config.ping_interval_ms < 100 ||
        s_config.ping_timeout_ms < 100 || s_config.timeout_threshold < 1 ||
        s_config.task_stack_size < 2048)
    {
        ESP_LOGE(PING_TAG, "Invalid configuration parameters");
        return ESP_ERR_INVALID_ARG;
    }
    if (s_config.enable_link_check && s_config.eth_handle == NULL)
    {
        ESP_LOGE(PING_TAG, "Link check enabled but no eth_handle provided");
        return ESP_ERR_INVALID_ARG;
    }

    s_ping_task_running = true;
    BaseType_t ret = xTaskCreate(ping_task, "ping_task", s_config.task_stack_size,
                                 netif, s_config.task_priority, &s_ping_task_handle);
    if (ret != pdPASS)
    {
        ESP_LOGE(PING_TAG, "Failed to create ping task");
        s_ping_task_running = false;
        return ESP_FAIL;
    }

    ESP_LOGI(PING_TAG, "Ping task started, poll_interval=%ldms, ping_interval=%ldms",
             s_config.poll_interval_ms, s_config.ping_interval_ms);
    return ESP_OK;
}

// 停止ping任务
esp_err_t ping_task_stop(void)
{
    if (s_ping_task_handle == NULL || !s_ping_task_running)
    {
        ESP_LOGW(PING_TAG, "Ping task not running");
        return ESP_ERR_INVALID_STATE;
    }

    s_ping_task_running = false;
    vTaskDelay(pdMS_TO_TICKS(100)); // 等待任务清理
    return ESP_OK;
}

// 检查任务状态
bool ping_task_is_running(void)
{
    return s_ping_task_running;
}